/***
 * KC031 GPIO操作函数
 * 
 * KC031的GPIO的proc地址如下：
 * 		/sys/class/aexgpio/aexgpio27
 * 
 * */
#ifndef __AEXGPIO_H__
#define __AEXGPIO_H__
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "utils.h"
// #include "head.h"

#define AEXIN_MIN_INDEX		F_AEXIN_MIN_INDEX()
#define AEXIN_MAX_INDEX		F_AEXIN_MAX_INDEX()
#define AEXOUT_MIN_INDEX	F_AEXOUT_MIN_INDEX()
#define AEXOUT_MAX_INDEX	F_AEXOUT_MAX_INDEX()
#define NUM_AEXGPIO_IN		F_NUM_AEXGPIO_IN()
#define NUM_AEXGPIO_OUT		F_NUM_AEXGPIO_OUT()
#define DEFAULT_GPIO_ADDR	F_DEFAULT_GPIO_ADDR()


unsigned int F_AEXIN_MIN_INDEX();
unsigned int F_AEXIN_MAX_INDEX();
unsigned int F_AEXOUT_MIN_INDEX();
unsigned int F_AEXOUT_MAX_INDEX();
unsigned int F_NUM_AEXGPIO_IN();
unsigned int F_NUM_AEXGPIO_OUT();
unsigned int F_DEFAULT_GPIO_ADDR();

/**
 * @brief 获得输入的掩码
 * 
 * @return unsigned long 
 */
static inline unsigned long AEXIN_MASK()
{
	unsigned long i,ret=0;
	for(i=AEXIN_MIN_INDEX;i<=AEXIN_MAX_INDEX;i++){
		ret |= 1<<i;
	}
	return ret;
}

/**
 * @brief 获得输出的掩码
 * 
 * @return unsigned long 
 */
static inline unsigned long AEXOUT_MASK()
{
	unsigned long i,ret=0;
	for(i=AEXOUT_MIN_INDEX;i<=AEXOUT_MAX_INDEX;i++){
		ret |= 1<<i;
	}
	return ret;
}

/**
 * aexgpio根据地址获取IO数值的函数，此函数需要各个模块根据模块设计来实现。
 * 
 * param 
 * 	address : GPIO的地址，可以是I2C地址，也可以是IO组序号，默认是0
 */
unsigned long aexgpio_getvalue(int address);
/**
 * aexgpio根据地址设置IO数值的函数，DO就是通过这个函数来设置输出状态的，此函数需要各个模块根据IO模块设计来实现。
 * param
 *   address : GPIO的地址，可以是I2C地址，也可以是IO组序号，默认是0
 *   value : 要设置的数值。
 */
void aexgpio_setvalue(int address,unsigned long value);
/**
 * 模块GPIO相关的初始化函数
 */
void aexgpio_init();
/**
 * 模块GPIO获取模块地址的函数，如果没有地址的概念则可以返回0。
 */
unsigned char aexgpio_get_mod_addr();

/**
 * 模块GPIO获取DI的数量
 */
unsigned char aexgpio_get_dinum(unsigned char addr);
/**
 * 模块GPIO获取DO的数量
 */
unsigned char aexgpio_get_donum(unsigned char addr);
/**
 * 模块GPIO获取AI的数量
 */
unsigned char aexgpio_get_ainum(unsigned char addr);
/**
 * 模块GPIO获取AI的数值，最大支持32位AD
 */
unsigned long aexgpio_get_ai(unsigned char addr,int index);
/**
 * 模块GPIO获取保持寄存器AO的数值，最大支持32位DA
 */
/**
 * 模块GPIO获取AO的数量
 */
unsigned char aexgpio_get_aonum(unsigned char addr);
unsigned long aexgpio_get_ao(unsigned char addr,int index);
/**
 * 模块GPIO设置保持寄存器AO的值，最大支持32位DA
 */
void aexgpio_set_ao(unsigned char addr,int index,unsigned long value);
/**
 * 模块的总线状态，如果没有可以用空函数实现
 */
void aexgpio_set_bus_status(int level);
/**
 * 模块的在线状态，如果没有可以用空函数实现
 */
void aexgpio_set_online_status(int level);
/**
 * 模块的故障状态，如果没有可以用空函数实现
 */
void aexgpio_set_error_status(int level);

unsigned long aexgpio_get_in();
unsigned long aexgpio_get_in_by_index(int index);
unsigned long aexgpio_get_out();
unsigned long aexgpio_get_out_by_index(int index);
void aexgpio_set_out(unsigned long mask,unsigned long value);
void aexgpio_set_out_by_index(unsigned int index,unsigned int level);
void aexgpio_set_out_invert(unsigned long mask);


static inline int aexgpio_get(int address,int index)
{
	int level = 0;
	unsigned long value;
	
	value = aexgpio_getvalue(address);
	if(index < 0) index = 0;
	if(index > 31)index = 31;
	level = value & (1<<index);
	return !!level;
}

/*
index 0--7
*/
static inline void aexgpio_set(int address,int index,int level)
{
	unsigned long value,mask;
	
	level = !!level;
	index += AEXOUT_MIN_INDEX;
	value = aexgpio_getvalue(address);
	// printf("read Value:%04x", value);
	if(index < 0) index = 0;
	if(index > 31)index = 31;
	mask = ~(1<<index);
	value &= mask;
	value |= level<<index;
	// printf("write Value:%04x", value);
	aexgpio_setvalue(address,value);
}

#define AEXGPIO_MAX_AIO_BYTE		4

unsigned char bits_to_bytes(unsigned char n_bits);
char *get_pdata_bit(char *wbuf,int wlen, unsigned char *bitv, int count);
char* uint32_array_to_csv(const uint8_t* buffer, size_t buf_size, char* output, size_t output_size);
char *get_utf8_printable(const unsigned char *buf, size_t size);

unsigned char aexgpio_set_pdata_dio(unsigned char *pdata,int index,unsigned char num,unsigned long value);
unsigned char aexgpio_set_pdata_ai(unsigned char addr,unsigned char *pdata,int index,unsigned char num);
unsigned char aexgpio_set_pdata_ao(unsigned char addr,unsigned char *pdata,int index,unsigned char num);

#endif //